# Copyright 2011 Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import calendar
import datetime
import time
import utils
from model import Item, Log, db
from django.utils import simplejson

NULL_TTL = datetime.timedelta(0, 3600)  # nulls disappear after 1 hour

def timestamp(dt):
    return calendar.timegm(dt.utctimetuple()) + dt.microsecond * 1e-6

class Main(utils.Handler):
    def get(self, verb):
        self.invoke('get_' + verb)

    def post(self, verb):
        self.invoke('post_' + verb)

    def invoke(self, method):
        self.response.headers['Access-Control-Allow-Origin'] = '*'
        method = getattr(self, method, None)
        if not method:
            raise utils.ErrorMessage(404, 'no such verb')
        method()

    def load_param(self, name):
        if name not in self.request.params:
            raise utils.ErrorMessage(400, 'missing param')
        try:
            return simplejson.loads(self.request.params[name])
        except:
            raise utils.ErrorMessage(400, 'invalid param')

    def get_get(self):
        key = self.load_param('key')
        item = Item.get_by_key_name(key)
        self.response.out.write(item and item.json_value or 'null')

    def get_history(self):
        key = self.load_param('key')
        history = Log.all().filter('string_key =', key).order('-updated')
        self.response.out.write(
            '[%s,[' % simplejson.dumps(key) +
            ','.join('[%.6f,%s]' % (timestamp(log.updated), log.json_value)
                     for log in history) +
            ']]'
        )
        
    def post_put(self):
        key = self.load_param('key')
        value = self.load_param('value')
        json_value = simplejson.dumps(value)
        if not isinstance(key, basestring):
            raise utils.ErrorMessage(400, 'invalid key')
        db.put([
            Item(key_name=key, json_value=json_value),
            Log(string_key=key, json_value=json_value,
                ip_addr=self.request.remote_addr)
        ])
        self.response.out.write(simplejson.dumps(key))

    def get_sync(self):
        now = int(time.time() * 1000)
        try:
            seconds = self.load_param('since')/1000.0
        except:
            raise utils.ErrorMessage(400, 'invalid param')
        min_updated = datetime.datetime.utcfromtimestamp(seconds)
        items = Item.all().filter('updated >=', min_updated).fetch(10000)
        self.response.out.write(
            '[%d,{' % now +
            ','.join('%s:%s' % (simplejson.dumps(item.key().name()),
                                item.json_value) for item in items) +
            '}]'
        )

    def get_clean(self):
        history_limit = datetime.datetime.utcnow() - NULL_TTL
        db.delete(Item.all(keys_only=True
                     ).filter('json_value =', 'null'
                     ).filter('updated <', history_limit).fetch(1000))

if __name__ == '__main__':
    utils.run(('/(\w+)', Main), debug=True)
